#include "SQLSelectQueryBlock.h"
#include <algorithm>
#include <set>
#include <map>


#include "../SQLName.h"
#include "../SQLSetQuantifier.h"
#include "../expr/SQLNullExpr.h"
#include "../expr/SQLInListExpr.h"
#include "../expr/SQLBinaryOpExprGroup.h"
#include "../expr/SQLBinaryOperator.h"
#include "../expr/SQLBinaryOpExpr.h"
#include "../expr/SQLMethodInvokeExpr.h"
#include "../expr/SQLBinaryOpExprGroup.h"
#include "../expr/SQLAllColumnExpr.h"
#include "../../../utils/instanceof.h"
#include "../../../utils/ifeq.h"
#include "../../../utils/log.h"
#include "../../../utils/FnvHash.h"
#include "../../parser/OdpsUDTFSQLSelectItem.h"
#include "../../visitor/SQLASTVisitor.h"
#include "SQLSelectItem.h"

#include "SQLSubqueryTableSource.h"

SETCALSS(SQLSelectQueryBlock);

SQLSelectQueryBlock::SQLSelectQueryBlock()
{
  selectList = std::make_shared<std::list<SQLSelectItem_ptr>>();
  windows = std::make_shared<std::list<SQLWindow_ptr>>();
  forUpdateOf = std::make_shared<std::list<SQLExpr_ptr>>();
  distributeBy = std::make_shared<std::list<SQLSelectOrderByItem_ptr>>();
  sortBy = std::make_shared<std::list<SQLSelectOrderByItem_ptr>>();
  clusterBy = std::make_shared<std::list<SQLSelectOrderByItem_ptr>>();
  hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
}

SQLSelectQueryBlock::SQLSelectQueryBlock(DbType_ptr dbType)
{
  if (dbType != nullptr)
  {
    this->dbType = dbType;
  }
  selectList = std::make_shared<std::list<SQLSelectItem_ptr>>();
  windows = std::make_shared<std::list<SQLWindow_ptr>>();
  forUpdateOf = std::make_shared<std::list<SQLExpr_ptr>>();
  distributeBy = std::make_shared<std::list<SQLSelectOrderByItem_ptr>>();
  sortBy = std::make_shared<std::list<SQLSelectOrderByItem_ptr>>();
  clusterBy = std::make_shared<std::list<SQLSelectOrderByItem_ptr>>();
  hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
}

SQLExprTableSource_ptr SQLSelectQueryBlock::getInto()
{
  return into;
}

void SQLSelectQueryBlock::setInto(SQLExpr_ptr into)
{
  this->setInto(SQLExprTableSource_ptr(new SQLExprTableSource(into)));
}

void SQLSelectQueryBlock::setInto(SQLExprTableSource_ptr into)
{
  if (into != NULL)
  {
    into->setParent(SharedObject(SQLSelectQueryBlock));
  }
  this->into = into;
}

SQLSelectGroupByClause_ptr SQLSelectQueryBlock::getGroupBy()
{
  return this->groupBy;
}

void SQLSelectQueryBlock::setGroupBy(SQLSelectGroupByClause_ptr x)
{
  if (x != NULL)
  {
    x->setParent(SharedObject(SQLSelectQueryBlock));
  }
  this->groupBy = x;
}

std::shared_ptr<std::list<SQLWindow_ptr>> SQLSelectQueryBlock::getWindows()
{
  return windows;
}

void SQLSelectQueryBlock::addWindow(SQLWindow_ptr x)
{
  if (x != NULL)
  {
    x->setParent(SharedObject(SQLSelectQueryBlock));
  }
  // if (windows == NULL) {
  //     windows = new ArrayList<SQLWindow*>(4);
  // }
  this->windows->push_back(x);
}

SQLExpr_ptr SQLSelectQueryBlock::getQualify()
{
  return qualify;
}

void SQLSelectQueryBlock::setQualify(SQLExpr_ptr x)
{
  if (x != NULL)
  {
    x->setParent(SharedObject(SQLSelectQueryBlock));
  }
  this->qualify = x;
}

SQLExpr_ptr SQLSelectQueryBlock::getWhere()
{
  return this->where;
}

void SQLSelectQueryBlock::setWhere(SQLExpr_ptr x)
{
  if (x != NULL)
  {
    x->setParent(SharedObject(SQLSelectQueryBlock));
  }
  this->where = x;
}

void SQLSelectQueryBlock::addWhere(SQLExpr_ptr condition)
{
  if (condition == NULL)
  {
    return;
  }

  if (where == NULL)
  {
    condition->setParent(SharedObject(SQLSelectQueryBlock));
    where = condition;
    return;
  }

  SQLExpr_list_ptr items = SQLBinaryOpExpr::split(where, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::BooleanAnd)));
  for (SQLExpr_ptr item : *items)
  {
    if (condition == item)
    {
      return;
    }

    if (instanceof <SQLExpr, SQLInListExpr>(condition))
    {
      SQLInListExpr_ptr inListExpr = std::dynamic_pointer_cast<SQLInListExpr>(condition);

      if (instanceof <SQLExpr, SQLBinaryOpExpr>(item))
      {
        SQLBinaryOpExpr_ptr binaryOpItem = std::dynamic_pointer_cast<SQLBinaryOpExpr>(item);
        SQLExpr_ptr left = binaryOpItem->getLeft();
        SQLExpr_ptr right = binaryOpItem->getRight();
        if (inListExpr->getExpr() == left &&
            binaryOpItem->getOperator()->name == SQLBinaryOperator::Equality.name &&
            !(instanceof <SQLExpr, SQLNullExpr>(right)))
        {
          std::list<SQLExpr_ptr>::iterator it = std::find(inListExpr->getTargetList()->begin(), inListExpr->getTargetList()->end(), right);
          if (it == inListExpr->getTargetList()->end())
          {
            return;
          }

          // SQLUtils::replaceInParent(item, new SQLBooleanExpr(BOOL::FALSE));
          return;
        }
      }
      else
      {
        if (instanceof <SQLExpr, SQLInListExpr>(item))
        {
          SQLInListExpr_ptr inListItem = std::dynamic_pointer_cast<SQLInListExpr>(item);
          if (inListExpr->getExpr() == inListItem->getExpr())
          {
            std::shared_ptr<std::map<SQLExpr_ptr, BOOL_ptr>> set_;
            for (SQLExpr_ptr itemItem : *inListItem->getTargetList())
            {
              set_->insert(std::pair<SQLExpr_ptr, BOOL_ptr>(itemItem, BOOL::TRUE));
            }

            SQLExpr_list_ptr andList = std::make_shared<std::list<SQLExpr_ptr>>();
            for (SQLExpr_ptr exprItem : *inListExpr->getTargetList())
            {
              std::map<SQLExpr_ptr, BOOL_ptr>::iterator it = set_->find(exprItem);
              if (it != set_->end())
              {
                andList->push_back(std::dynamic_pointer_cast<SQLExpr>(exprItem->clone()));
              }
            }

            if (andList->empty())
            {
              // SQLUtils::replaceInParent(item, new SQLBooleanExpr(BOOL::FALSE));
              return;
            }

            inListItem->getTargetList()->clear();
            for (SQLExpr_ptr val : *andList)
            {
              // inListItem->addTarget(val);
            }
            return;
          }
        }
      }
    }
  }

  where = SQLBinaryOpExpr::and_(this->where, condition);
  where->setParent(SharedObject(SQLSelectQueryBlock));
}

void SQLSelectQueryBlock::addWhereForDynamicFilter(SQLExpr_ptr condition)
{
  if (condition == NULL)
  {
    return;
  }

  if (where == NULL)
  {
    // condition->setParent(this);
    where = condition;
    return;
  }

  if ((instanceof <SQLExpr, SQLBinaryOpExpr>(where) || instanceof <SQLExpr, SQLBinaryOpExprGroup>(where)))
  {
    SQLExpr_list_ptr items = SQLBinaryOpExpr::split(where, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::BooleanAnd)));
    for (SQLExpr_ptr item : *items)
    {
      if (condition == item)
      {
        return;
      }

      if (instanceof <SQLExpr, SQLInListExpr>(condition))
      {
        SQLInListExpr_ptr inListExpr = std::dynamic_pointer_cast<SQLInListExpr>(condition);

        if (instanceof <SQLExpr, SQLBinaryOpExpr>(item))
        {
          SQLBinaryOpExpr_ptr binaryOpItem = std::dynamic_pointer_cast<SQLBinaryOpExpr>(item);
          SQLExpr_ptr left = binaryOpItem->getLeft();
          SQLExpr_ptr right = binaryOpItem->getRight();
          if (inListExpr->getExpr() == left)
          {
            std::list<SQLExpr_ptr>::iterator it = std::find(inListExpr->getTargetList()->begin(), inListExpr->getTargetList()->end(), right);
            // if (inListExpr->getTargetList()->contains(right))
            if (it != inListExpr->getTargetList()->end())
            {
              replace(item, inListExpr);
            }
            else
            {
              SQLInListExpr_ptr inListExpr2 = std::dynamic_pointer_cast<SQLInListExpr>(inListExpr->clone());
              inListExpr2->addTarget(std::dynamic_pointer_cast<SQLExpr>(right->clone()));
              replace(item, inListExpr2);
            }
            return;
          }
        }
        else
        {
          if (instanceof <SQLExpr, SQLInListExpr>(item))
          {
            SQLInListExpr_ptr inListItem = std::dynamic_pointer_cast<SQLInListExpr>(item);
            if (inListExpr->getExpr() == inListItem->getExpr())
            {
              std::set<SQLExpr_ptr> set;
              for (SQLExpr_ptr itemItem : *inListItem->getTargetList())
              {
                set.insert(itemItem);
              }
              for (SQLExpr_ptr exprItem : *inListExpr->getTargetList())
              {
                if (!(set.count(exprItem) > 0))
                {
                  inListItem->addTarget(std::dynamic_pointer_cast<SQLExpr>(exprItem->clone()));
                }
              }
              return;
            }
          }
        }
      }
    }
  }

  where = SQLBinaryOpExpr::and_(this->where, condition);
  // where->setParent(this);
}

void SQLSelectQueryBlock::whereOr(SQLExpr_ptr condition)
{
  if (condition == NULL)
  {
    return;
  }

  if (where == NULL)
  {
    // condition->setParent(this);
    where = condition;
  }
  else if (SQLBinaryOpExpr::isOr(where) || SQLBinaryOpExpr::isOr(condition))
  {
    SQLBinaryOpExprGroup_ptr group = SQLBinaryOpExprGroup_ptr(new SQLBinaryOpExprGroup(SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::BooleanOr)), dbType));
    group->add(where);
    group->add(condition);
    group->setParent(SharedObject(SQLSelectQueryBlock));
    where = group;
  }
  else
  {
    where = SQLBinaryOpExpr::or_(where, condition);
    // where->setParent(this);
  }
}

void SQLSelectQueryBlock::addHaving(SQLExpr_ptr condition)
{
  if (condition == NULL)
  {
    return;
  }

  if (groupBy == NULL)
  {
    groupBy = SQLSelectGroupByClause_ptr(new SQLSelectGroupByClause());
  }

  groupBy->addHaving(condition);
}

SQLOrderBy_ptr SQLSelectQueryBlock::getOrderBy()
{
  return orderBy;
}

void SQLSelectQueryBlock::setOrderBy(SQLOrderBy_ptr orderBy)
{
  if (orderBy != NULL)
  {
    orderBy->setParent(SharedObject(SQLSelectQueryBlock));
  }

  this->orderBy = orderBy;
}

void SQLSelectQueryBlock::addOrderBy(SQLOrderBy_ptr orderBy)
{
  if (orderBy == NULL)
  {
    return;
  }

  if (this->orderBy == NULL)
  {
    setOrderBy(orderBy);
    return;
  }

  for (SQLSelectOrderByItem_ptr item : *orderBy->getItems())
  {
    this->orderBy->addItem(std::dynamic_pointer_cast<SQLExpr>(item->clone()));
  }
}

void SQLSelectQueryBlock::addOrderBy(SQLSelectOrderByItem_ptr orderByItem)
{
  if (orderByItem == NULL)
  {
    return;
  }

  if (this->orderBy == NULL)
  {
    orderBy = SQLOrderBy_ptr(new SQLOrderBy());
    orderBy->setParent(SharedObject(SQLSelectQueryBlock));
  }

  orderBy->addItem(orderByItem);
}

BOOL_ptr SQLSelectQueryBlock::containsOrderBy(SQLSelectOrderByItem_ptr orderByItem)
{
  if (orderByItem == NULL || this->orderBy == NULL)
  {
    return BOOL::FALSE;
  }

  std::list<SQLSelectOrderByItem_ptr>::iterator it = std::find(this->orderBy->getItems()->begin(), this->orderBy->getItems()->end(), orderByItem);
  // if (this->orderBy->getItems()->contains(orderByItem))
  if (it != this->orderBy->getItems()->end())
  {
    return BOOL::TRUE;
  }

  SQLExpr_ptr expr = orderByItem->getExpr();
  if (expr == NULL && instanceof <SQLExpr, SQLIntegerExpr>(expr))
  {
    return BOOL::FALSE;
  }

  int index = 0;
  std::list<SQLSelectItem_ptr>::iterator it_ = selectList->begin();
  for (int i = 0; i < selectList->size(); i++)
  {
    std::advance(it_, i); // 迭代器前进i个元素，注意i是从0开始
    SQLSelectItem_ptr selectItem = (*it_);
    if (selectItem->getExpr() == expr)
    {
      index = i + 1;
      break;
    }
  }

  if (index > 0)
  {
    for (SQLSelectOrderByItem_ptr selectOrderByItem : *orderBy->getItems())
    {
      SQLExpr_ptr orderByItemExpr = selectOrderByItem->getExpr();
      if (instanceof <SQLExpr, SQLIntegerExpr>(orderByItemExpr))
      {
        double num = (std::dynamic_pointer_cast<SQLIntegerExpr>(orderByItemExpr))->getNumber();
        if (num == index)
        {
          return BOOL::TRUE;
        }
      }
    }
  }

  return BOOL::FALSE;
}

void SQLSelectQueryBlock::addOrderBy(SQLExpr_ptr orderBy, SQLOrderingSpecification_ptr type)
{
  if (orderBy == NULL)
  {
    return;
  }

  if (this->orderBy == NULL)
  {
    setOrderBy(SQLOrderBy_ptr(new SQLOrderBy(orderBy, type)));
    return;
  }

  this->orderBy->addItem(orderBy, type);
}

void SQLSelectQueryBlock::addOrderBy(SQLExpr_ptr orderBy)
{
  if (orderBy == NULL)
  {
    return;
  }

  if (this->orderBy == NULL)
  {
    setOrderBy(SQLOrderBy_ptr(new SQLOrderBy(orderBy)));
    return;
  }

  this->orderBy->addItem(orderBy);
}

SQLOrderBy_ptr SQLSelectQueryBlock::getOrderBySiblings()
{
  return orderBySiblings;
}

void SQLSelectQueryBlock::setOrderBySiblings(SQLOrderBy_ptr orderBySiblings)
{
  if (orderBySiblings != NULL)
  {
    orderBySiblings->setParent(SharedObject(SQLSelectQueryBlock));
  }
  this->orderBySiblings = orderBySiblings;
}

int SQLSelectQueryBlock::getDistionOption()
{
  return this->distionOption;
}

void SQLSelectQueryBlock::setDistionOption(int distionOption)
{
  this->distionOption = distionOption;
}

void SQLSelectQueryBlock::setDistinct()
{
  this->distionOption = SQLSetQuantifier::DISTINCT;
}

BOOL_ptr SQLSelectQueryBlock::isDistinct()
{
  return (this->distionOption == SQLSetQuantifier::DISTINCT)?BOOL::TRUE:BOOL::FALSE;
}

SQLSelectItem_list_ptr SQLSelectQueryBlock::getSelectList()
{
  return this->selectList;
}

SQLSelectItem_ptr SQLSelectQueryBlock::getSelectItem(int i)
{
  std::list<SQLSelectItem_ptr>::iterator it = this->selectList->begin();
  std::advance(it, i); // 迭代器前进i个元素，注意i是从0开始
  return (*it);
}

void SQLSelectQueryBlock::addSelectItem(SQLSelectItem_ptr item)
{
  LOG_INFO << __FUNCTION__ << ": addSelectItem";
  this->selectList->push_back(item);
  // item->setParent(this);
}

SQLSelectItem_ptr SQLSelectQueryBlock::addSelectItem(SQLExpr_ptr expr)
{
  LOG_INFO << __FUNCTION__ << ": addSelectItem";
  SQLSelectItem_ptr item = SQLSelectItem_ptr(new SQLSelectItem(expr));
  this->addSelectItem(item);
  return item;
}

void SQLSelectQueryBlock::addSelectItem(string_ptr selectItemExpr, string_ptr alias)
{
  LOG_INFO << __FUNCTION__ << ": addSelectItem";
  SQLExpr_ptr expr = SQLUtils::toSQLExpr(selectItemExpr, dbType);
  this->addSelectItem(SQLSelectItem_ptr(new SQLSelectItem(expr, alias)));
}

void SQLSelectQueryBlock::addSelectItem(SQLExpr_ptr expr, string_ptr alias)
{
  LOG_INFO << __FUNCTION__ << ": addSelectItem";
  this->addSelectItem(SQLSelectItem_ptr(new SQLSelectItem(expr, alias)));
}

BOOL_ptr SQLSelectQueryBlock::hasSelectAggregation()
{
  AggregationStatVisitor *v = new AggregationStatVisitor();
  for (SQLSelectItem_ptr item : *selectList)
  {
    SQLExpr_ptr expr = item->getExpr();
    // expr->accept(v);
  }
  return v->aggregation;
}

SQLTableSource_ptr SQLSelectQueryBlock::getFrom()
{
  return this->from;
}

void SQLSelectQueryBlock::setFrom(SQLExpr_ptr from)
{
  setFrom(SQLExprTableSource_ptr(new SQLExprTableSource(from)));
}

void SQLSelectQueryBlock::setFrom(SQLTableSource_ptr from)
{
  // if (from != NULL)
  // {
  //   from->setParent(this);
  // }
  this->from = from;
}

void SQLSelectQueryBlock::setFrom(SQLSelectQueryBlock_ptr queryBlock, string_ptr alias)
{
  if (queryBlock == NULL)
  {
    this->from = NULL;
    return;
  }

  this->setFrom(SQLSelect_ptr(new SQLSelect(queryBlock)), alias);
}

void SQLSelectQueryBlock::setFrom(SQLSelect_ptr select, string_ptr alias)
{
  if (select == NULL)
  {
    this->from = NULL;
    return;
  }

  std::shared_ptr<SQLSubqueryTableSource> from = std::shared_ptr<SQLSubqueryTableSource>(new SQLSubqueryTableSource(select));
  from->setAlias(alias);
  this->setFrom(from);
}

void SQLSelectQueryBlock::setFrom(string_ptr tableName, string_ptr alias)
{
  SQLExprTableSource_ptr from;
  if (tableName->empty() || tableName->length() == 0)
  {
    from = NULL;
  }
  else
  {
    SQLExpr_ptr expr = SQLUtils::toSQLExpr(tableName);
    from = SQLExprTableSource_ptr(new SQLExprTableSource(expr, alias));
  }
  this->setFrom(from);
}

BOOL_ptr SQLSelectQueryBlock::isForUpdate()
{
  return forUpdate;
}

void SQLSelectQueryBlock::setForUpdate(BOOL_ptr forUpdate)
{
  this->forUpdate = forUpdate;
}

BOOL_ptr SQLSelectQueryBlock::isNoWait()
{
  return noWait;
}

void SQLSelectQueryBlock::setNoWait(BOOL_ptr noWait)
{
  this->noWait = noWait;
}

BOOL_ptr SQLSelectQueryBlock::isSkipLocked()
{
  return skipLocked;
}

void SQLSelectQueryBlock::setSkipLocked(BOOL_ptr skipLocked)
{
  this->skipLocked = skipLocked;
}

BOOL_ptr SQLSelectQueryBlock::isForShare()
{
  return forShare;
}

void SQLSelectQueryBlock::setForShare(BOOL_ptr forShare)
{
  this->forShare = forShare;
}

SQLExpr_ptr SQLSelectQueryBlock::getWaitTime()
{
  return waitTime;
}

void SQLSelectQueryBlock::setWaitTime(SQLExpr_ptr waitTime)
{
  // if (waitTime != NULL)
  // {
  //   waitTime->setParent(this);
  // }
  this->waitTime = waitTime;
}

SQLLimit_ptr SQLSelectQueryBlock::getLimit()
{
  return limit_;
}

void SQLSelectQueryBlock::setLimit(SQLLimit_ptr limit)
{
  if (limit != NULL)
  {
    limit->setParent(SharedObject(SQLSelectQueryBlock));
  }
  this->limit_ = limit;
}

void SQLSelectQueryBlock::mergeLimit(SQLLimit_ptr limit)
{
  if (this->limit_ == NULL)
  {
    this->limit_ = std::dynamic_pointer_cast<SQLLimit>(limit->clone());
    return;
  }

  this->limit_->merge(limit);
}

SQLExpr_ptr SQLSelectQueryBlock::getFirst()
{
  if (limit_ == NULL)
  {
    return NULL;
  }

  return limit_->getRowCount();
}

void SQLSelectQueryBlock::setFirst(SQLExpr_ptr first)
{
  if (limit_ == NULL)
  {
    limit_ = SQLLimit_ptr(new SQLLimit());
  }
  this->limit_->setRowCount(first);
}

SQLExpr_ptr SQLSelectQueryBlock::getOffset()
{
  if (limit_ == NULL)
  {
    return NULL;
  }

  return limit_->getOffset();
}

void SQLSelectQueryBlock::setOffset(SQLExpr_ptr offset)
{
  if (limit_ == NULL)
  {
    limit_ = SQLLimit_ptr(new SQLLimit());
  }
  this->limit_->setOffset(offset);
}

BOOL_ptr SQLSelectQueryBlock::isPrior()
{
  return prior;
}

void SQLSelectQueryBlock::setPrior(BOOL_ptr prior)
{
  this->prior = prior;
}

SQLExpr_ptr SQLSelectQueryBlock::getStartWith()
{
  return this->startWith;
}

void SQLSelectQueryBlock::setStartWith(SQLExpr_ptr startWith)
{
  // if (startWith != NULL)
  // {
  //   startWith->setParent(this);
  // }
  this->startWith = startWith;
}

SQLExpr_ptr SQLSelectQueryBlock::getConnectBy()
{
  return this->connectBy;
}

void SQLSelectQueryBlock::setConnectBy(SQLExpr_ptr connectBy)
{
  // if (connectBy != NULL)
  // {
  //   connectBy->setParent(this);
  // }
  this->connectBy = connectBy;
}

BOOL_ptr SQLSelectQueryBlock::isNoCycle()
{
  return this->noCycle;
}

void SQLSelectQueryBlock::setNoCycle(BOOL_ptr noCycle)
{
  this->noCycle = noCycle;
}

SQLSelectOrderByItem_list_ptr SQLSelectQueryBlock::getDistributeBy()
{
  // if (distributeBy == NULL)
  // {
  //   distributeBy = new ArrayList<SQLSelectOrderByItem_ptr >();
  // }

  return distributeBy;
}

SQLSelectOrderByItem_list_ptr SQLSelectQueryBlock::getDistributeByDirect()
{
  return distributeBy;
}

void SQLSelectQueryBlock::addDistributeBy(SQLExpr_ptr x)
{
  if (x != NULL)
  {
    // x->setParent(this);
  }
  else
  {
    return;
  }

  // if (distributeBy == NULL)
  // {
  //   distributeBy = new ArrayList<SQLSelectOrderByItem_ptr >();
  // }
  distributeBy->push_back(SQLSelectOrderByItem_ptr(new SQLSelectOrderByItem(x)));
}

void SQLSelectQueryBlock::addDistributeBy(SQLSelectOrderByItem_ptr item)
{
  // if (distributeBy == NULL)
  // {
  //   distributeBy = new ArrayList<SQLSelectOrderByItem_ptr >();
  // }
  // if (item != NULL)
  // {
  //   item->setParent(this);
  // }
  this->distributeBy->push_back(item);
}

SQLSelectOrderByItem_list_ptr SQLSelectQueryBlock::getSortBy()
{
  // if (sortBy == NULL)
  // {
  //   sortBy = new ArrayList<SQLSelectOrderByItem_ptr >();
  // }
  return sortBy;
}

SQLSelectOrderByItem_list_ptr SQLSelectQueryBlock::getSortByDirect()
{
  return sortBy;
}

void SQLSelectQueryBlock::addSortBy(SQLSelectOrderByItem_ptr item)
{
  // if (sortBy == NULL)
  // {
  //   sortBy = new ArrayList<SQLSelectOrderByItem_ptr >();
  // }
  if (item != NULL)
  {
    item->setParent(SharedObject(SQLSelectQueryBlock));
  }
  this->sortBy->push_back(item);
}

void SQLSelectQueryBlock::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLSelectQueryBlock)))
  {
    auto it_selectList = this->selectList->begin();
    for (int i = 0; i < this->selectList->size(); i++)
    {
      std::advance(it_selectList, i);
      SQLSelectItem_ptr item = (*it_selectList);
      if (item != NULL)
      {
        item->accept(visitor);
      }
    }

    if (this->from != NULL)
    {
      this->from->accept(visitor);
    }

    // if (this->windows != NULL) {
    //     for (int i = 0; i < windows->size(); i++) {
    //         SQLWindow* item = windows->get(i);
    //         item->accept(visitor);
    //     }
    // }

    if (this->into != NULL)
    {
      this->into->accept(visitor);
    }

    if (this->where != NULL)
    {
      this->where->accept(visitor);
    }

    if (this->startWith != NULL)
    {
      this->startWith->accept(visitor);
    }

    if (this->connectBy != NULL)
    {
      this->connectBy->accept(visitor);
    }

    if (this->groupBy != NULL)
    {
      this->groupBy->accept(visitor);
    }

    if (this->orderBy != NULL)
    {
      this->orderBy->accept(visitor);
    }

    if (!this->distributeBy->empty())
    {
      auto it_distributeBy = this->distributeBy->begin();
      for (int i = 0; i < this->distributeBy->size(); i++)
      {
        std::advance(it_distributeBy, i);
        SQLSelectOrderByItem_ptr item = (*it_distributeBy);
        item->accept(visitor);
      }
    }

    if (!this->sortBy->empty())
    {
      auto it_sortBy = this->sortBy->begin();
      for (int i = 0; i < this->sortBy->size(); i++)
      {
        std::advance(it_sortBy, i);
        SQLSelectOrderByItem_ptr item = (*it_sortBy);
        item->accept(visitor);
      }
    }

    if (this->waitTime != NULL)
    {
      this->waitTime->accept(visitor);
    }

    if (this->limit_ != NULL)
    {
      this->limit_->accept(visitor);
    }
  }
  visitor->endVisit(SharedObject(SQLSelectQueryBlock));
}

bool SQLSelectQueryBlock::equals(Object_ptr o)
{
  if (this == o.get())
  {
    return true;
  }
  if (o == NULL || getClass() != o->getClass())
  {
    return false;
  }

  SQLSelectQueryBlock_ptr that = std::dynamic_pointer_cast<SQLSelectQueryBlock>(o);

  if (distionOption != that->distionOption)
  {
    return false;
  }
  if (prior != that->prior)
  {
    return false;
  }
  if (noCycle != that->noCycle)
  {
    return false;
  }
  if (parenthesized != that->parenthesized)
  {
    return false;
  }
  if (forUpdate != that->forUpdate)
  {
    return false;
  }
  if (noWait != that->noWait)
  {
    return false;
  }
  if (cachedSelectListHash != that->cachedSelectListHash)
  {
    return false;
  }
  if (!selectList->empty() ? !(selectList == that->selectList) : !that->selectList->empty())
  {
    return false;
  }
  if (from != NULL ? !(from == that->from) : that->from != NULL)
  {
    return false;
  }
  if (into != NULL ? !(into == that->into) : that->into != NULL)
  {
    return false;
  }
  if (where != NULL ? !(where == that->where) : that->where != NULL)
  {
    return false;
  }
  if (startWith != NULL ? !(startWith == that->startWith) : that->startWith != NULL)
  {
    return false;
  }
  if (connectBy != NULL ? !(connectBy == that->connectBy) : that->connectBy != NULL)
  {
    return false;
  }
  if (orderBySiblings != NULL ? !(orderBySiblings == that->orderBySiblings) : that->orderBySiblings != NULL)
  {
    return false;
  }
  if (groupBy != NULL ? !(groupBy == that->groupBy) : that->groupBy != NULL)
  {
    return false;
  }
  if (orderBy != NULL ? !(orderBy == that->orderBy) : that->orderBy != NULL)
  {
    return false;
  }
  if (waitTime != NULL ? !(waitTime == that->waitTime) : that->waitTime != NULL)
  {
    return false;
  }
  if (limit_ != NULL ? !(limit_ == that->limit_) : that->limit_ != NULL)
  {
    return false;
  }
  if (!forUpdateOf->empty() ? !(forUpdateOf == that->forUpdateOf) : !that->forUpdateOf->empty())
  {
    return false;
  }
  if (!distributeBy->empty() ? !(distributeBy == that->distributeBy) : !that->distributeBy->empty())
  {
    return false;
  }
  if (!sortBy->empty() ? !(sortBy == that->sortBy) : !that->sortBy->empty())
  {
    return false;
  }
  if (!cachedSelectList->empty() ? !(cachedSelectList == that->cachedSelectList) : !that->cachedSelectList->empty())
  {
    return false;
  }
  if (!(dbType == that->dbType))
  {
    return false;
  }
  return !hints->empty() ? (hints == that->hints) : !that->hints->empty();
}

int SQLSelectQueryBlock::hashCode()
{
  int result = distionOption;
  // result = 31 * result + (!selectList.empty()? selectList->hashCode() : 0);
  // result = 31 * result + (from != NULL ? from->hashCode() : 0);
  // result = 31 * result + (into != NULL ? into->hashCode() : 0);
  // result = 31 * result + (where != NULL ? where->hashCode() : 0);
  // result = 31 * result + (startWith != NULL ? startWith->hashCode() : 0);
  // result = 31 * result + (connectBy != NULL ? connectBy->hashCode() : 0);
  result = 31 * result + (prior ? 1 : 0);
  result = 31 * result + (noCycle ? 1 : 0);
  // result = 31 * result + (orderBySiblings != NULL ? orderBySiblings->hashCode() : 0);
  // result = 31 * result + (groupBy != NULL ? groupBy->hashCode() : 0);
  // result = 31 * result + (orderBy != NULL ? orderBy->hashCode() : 0);
  result = 31 * result + (parenthesized ? 1 : 0);
  result = 31 * result + (forUpdate ? 1 : 0);
  result = 31 * result + (noWait ? 1 : 0);
  // result = 31 * result + (waitTime != NULL ? waitTime->hashCode() : 0);
  // result = 31 * result + (limit_ != NULL ? limit_->hashCode() : 0);
  // result = 31 * result + (forUpdateOf != NULL ? forUpdateOf->hashCode() : 0);
  // result = 31 * result + (distributeBy != NULL ? distributeBy->hashCode() : 0);
  // result = 31 * result + (sortBy != NULL ? sortBy->hashCode() : 0);
  // result = 31 * result + (cachedSelectList != NULL ? cachedSelectList->hashCode() : 0);
  result = 31 * result + (int)(cachedSelectListHash ^ (cachedSelectListHash >> 32));
  // result = 31 * result + (dbType != NULL ? dbType->hashCode() : 0);
  // result = 31 * result + (hints != NULL ? hints->hashCode() : 0);
  return result;
}

BOOL_ptr SQLSelectQueryBlock::equalsForMergeJoin(SQLSelectQueryBlock *that)
{
  if (this == that)
  {
    return BOOL::TRUE;
  }
  if (that == NULL)
  {
    return BOOL::FALSE;
  }

  if (into != NULL || limit_ != NULL || groupBy != NULL)
  {
    return BOOL::FALSE;
  }

  if (distionOption != that->distionOption)
  {
    return BOOL::FALSE;
  }
  if (prior != that->prior)
  {
    return BOOL::FALSE;
  }
  if (noCycle != that->noCycle)
  {
    return BOOL::FALSE;
  }
  if (parenthesized != that->parenthesized)
  {
    return BOOL::FALSE;
  }
  if (forUpdate != that->forUpdate)
  {
    return BOOL::FALSE;
  }
  if (noWait != that->noWait)
  {
    return BOOL::FALSE;
  }
  if (cachedSelectListHash != that->cachedSelectListHash)
  {
    return BOOL::FALSE;
  }
  if (!selectList->empty() ? !(selectList == that->selectList) : !that->selectList->empty())
  {
    return BOOL::FALSE;
  }
  if (from != NULL ? !(from == that->from) : that->from != NULL)
  {
    return BOOL::FALSE;
  }
  if (into != NULL ? !(into == that->into) : that->into != NULL)
  {
    return BOOL::FALSE;
  }
  //        if (where != NULL ? !where->equals(that->where) : that->where != NULL) return BOOL::FALSE;
  if (startWith != NULL ? !(startWith == that->startWith) : that->startWith != NULL)
  {
    return BOOL::FALSE;
  }
  if (connectBy != NULL ? !(connectBy == that->connectBy) : that->connectBy != NULL)
  {
    return BOOL::FALSE;
  }
  if (orderBySiblings != NULL ? !(orderBySiblings == that->orderBySiblings) : that->orderBySiblings != NULL)
  {
    return BOOL::FALSE;
  }
  if (groupBy != NULL ? !(groupBy == that->groupBy) : that->groupBy != NULL)
  {
    return BOOL::FALSE;
  }
  if (orderBy != NULL ? !(orderBy == that->orderBy) : that->orderBy != NULL)
  {
    return BOOL::FALSE;
  }
  if (waitTime != NULL ? !(waitTime == that->waitTime) : that->waitTime != NULL)
  {
    return BOOL::FALSE;
  }
  if (limit_ != NULL ? !(limit_ == that->limit_) : that->limit_ != NULL)
  {
    return BOOL::FALSE;
  }
  if (!forUpdateOf->empty() ? !(forUpdateOf == that->forUpdateOf) : !that->forUpdateOf->empty())
  {
    return BOOL::FALSE;
  }
  if (!distributeBy->empty() ? !(distributeBy == that->distributeBy) : !that->distributeBy->empty())
  {
    return BOOL::FALSE;
  }
  if (!sortBy->empty() ? !(sortBy == that->sortBy) : !that->sortBy->empty())
  {
    return BOOL::FALSE;
  }
  if (!cachedSelectList->empty() ? !(cachedSelectList == that->cachedSelectList) : !that->cachedSelectList->empty())
  {
    return BOOL::FALSE;
  }
  return (dbType == that->dbType)?BOOL::TRUE:BOOL::FALSE;
}

// SQLSelectQueryBlock *SQLSelectQueryBlock::clone()
SQLObject_ptr SQLSelectQueryBlock::clone()
{
  SQLObject_ptr clone_tmp = SQLSelectQueryBlock_ptr(new SQLSelectQueryBlock(dbType));
  SQLSelectQueryBlock_ptr clone_res = std::dynamic_pointer_cast<SQLSelectQueryBlock>(clone_tmp);

  // return clone_res;

  // SQLSelectQueryBlock *x = new SQLSelectQueryBlock(&dbType);
  cloneTo(clone_res);
  return clone_res;
}

SQLExpr_list_ptr SQLSelectQueryBlock::getForUpdateOf()
{
  // if (forUpdateOf == NULL)
  // {
  //   forUpdateOf = new ArrayList<SQLExpr_ptr >(1);
  // }
  return forUpdateOf;
}

int SQLSelectQueryBlock::getForUpdateOfSize()
{
  if (forUpdateOf->empty())
  {
    return 0;
  }

  return forUpdateOf->size();
}

void SQLSelectQueryBlock::cloneSelectListTo(SQLSelectQueryBlock *x)
{
  x->distionOption = distionOption;
  for (SQLSelectItem_ptr item : *this->selectList)
  {
    SQLSelectItem_ptr item2 = std::dynamic_pointer_cast<SQLSelectItem>(item->clone());
    item2->setParent(SharedObject(SQLSelectQueryBlock));
    x->selectList->push_back(item2);
  }
}

void SQLSelectQueryBlock::cloneTo(SQLSelectQueryBlock_ptr x)
{
  x->parenthesized = parenthesized;
  x->distionOption = distionOption;

  if (x->selectList->size() > 0)
  {
    x->selectList->clear();
  }

  if (!hints->empty())
  {
    for (SQLCommentHint_ptr hint : *hints)
    {
      SQLCommentHint_ptr hint1 = std::dynamic_pointer_cast<SQLCommentHint>(hint->clone());
      hint1->SQLObjectImpl::setParent(x);
      x->getHints()->push_back(hint1);
    }
  }

  for (SQLSelectItem_ptr item : *this->selectList)
  {
    LOG_INFO << __FUNCTION__ << ": addSelectItem";
    x->addSelectItem(std::dynamic_pointer_cast<SQLSelectItem>(item->clone()));
  }

  if (from != NULL)
  {
    x->setFrom(std::dynamic_pointer_cast<SQLExpr>(from->clone()));
  }

  if (into != NULL)
  {
    x->setInto(std::dynamic_pointer_cast<SQLExpr>(into->clone()));
  }

  if (where != NULL)
  {
    x->setWhere(std::dynamic_pointer_cast<SQLExpr>(where->clone()));
  }

  if (startWith != NULL)
  {
    x->setStartWith(std::dynamic_pointer_cast<SQLExpr>(startWith->clone()));
  }

  if (connectBy != NULL)
  {
    x->setConnectBy(std::dynamic_pointer_cast<SQLExpr>(connectBy->clone()));
  }

  x->prior = prior;
  x->noCycle = noCycle;

  if (orderBySiblings != NULL)
  {
    x->setOrderBySiblings(std::dynamic_pointer_cast<SQLOrderBy>(orderBySiblings->clone()));
  }

  if (groupBy != NULL)
  {
    x->setGroupBy(std::dynamic_pointer_cast<SQLSelectGroupByClause>(groupBy->clone()));
  }

  if (orderBy != NULL)
  {
    x->setOrderBy(std::dynamic_pointer_cast<SQLOrderBy>(orderBy->clone()));
  }

  if (!distributeBy->empty())
  {
    // if (x->distributeBy == NULL)
    // {
    //   x->distributeBy = new ArrayList<SQLSelectOrderByItem_ptr >();
    // }

    std::list<SQLSelectOrderByItem_ptr>::iterator it = distributeBy->begin();
    for (int i = 0; i < distributeBy->size(); i++)
    {
      std::advance(it, i);
      SQLSelectOrderByItem_ptr item = std::dynamic_pointer_cast<SQLSelectOrderByItem>((*it)->clone());
      item->setParent(x);
      x->distributeBy->push_back(item);
    }
  }

  if (!sortBy->empty())
  {
    // if (x->sortBy == NULL)
    // {
    //   x->sortBy = new ArrayList<SQLSelectOrderByItem_ptr >();
    // }
    std::list<SQLSelectOrderByItem_ptr>::iterator it = sortBy->begin();
    for (int i = 0; i < sortBy->size(); i++)
    {
      std::advance(it, i);
      SQLSelectOrderByItem_ptr item = std::dynamic_pointer_cast<SQLSelectOrderByItem>((*it)->clone());
      item->setParent(x);
      x->sortBy->push_back(item);
    }
  }

  if (!clusterBy->empty())
  {
    // if (x->clusterBy == NULL)
    // {
    //   x->clusterBy = new ArrayList<SQLSelectOrderByItem_ptr >();
    // }
    std::list<SQLSelectOrderByItem_ptr>::iterator it = clusterBy->begin();
    for (int i = 0; i < clusterBy->size(); i++)
    {
      std::advance(it, i);
      SQLSelectOrderByItem_ptr item = std::dynamic_pointer_cast<SQLSelectOrderByItem>((*it)->clone());
      item->setParent(x);
      x->clusterBy->push_back(item);
    }
  }

  x->parenthesized = parenthesized;
  x->forUpdate = forUpdate;
  x->noWait = noWait;
  x->skipLocked = skipLocked;
  x->forShare = forShare;
  if (waitTime != NULL)
  {
    x->setWaitTime(std::dynamic_pointer_cast<SQLExpr>(waitTime->clone()));
  }

  if (limit_ != NULL)
  {
    x->setLimit(std::dynamic_pointer_cast<SQLLimit>(limit_->clone()));
  }
}

SQLTableSource_ptr SQLSelectQueryBlock::findTableSource(string_ptr alias)
{
  if (from == NULL)
  {
    return NULL;
  }
  return from->findTableSource(alias);
}

SQLTableSource_ptr SQLSelectQueryBlock::findTableSourceWithColumn(string_ptr column)
{
  if (from == NULL)
  {
    return NULL;
  }
  return from->findTableSourceWithColumn(column);
}

SQLTableSource_ptr SQLSelectQueryBlock::findTableSourceWithColumn(long columnHash)
{
  if (from == NULL)
  {
    return NULL;
  }

  SQLTableSource_ptr tableSource = from->findTableSourceWithColumn(columnHash);

  if (tableSource == NULL && instanceof <SQLTableSource, SQLExprTableSource>(from))
  {
    SQLSelectItem_ptr selectItem = this->findSelectItem(columnHash);
    if (selectItem != NULL && instanceof <SQLExpr, SQLName>(selectItem->getExpr()) && (std::dynamic_pointer_cast<SQLName>(selectItem->getExpr()))->nameHashCode64() == columnHash)
    {
      tableSource = from;
    }
  }

  return tableSource;
}

BOOL_ptr SQLSelectQueryBlock::replace(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  if (where == expr)
  {
    setWhere(target);
    return BOOL::TRUE;
  }

  if (startWith == expr)
  {
    setStartWith(target);
    return BOOL::TRUE;
  }

  if (connectBy == expr)
  {
    setConnectBy(target);
    return BOOL::TRUE;
  }
  return BOOL::FALSE;
}

SQLSelectItem_ptr SQLSelectQueryBlock::findSelectItem(string_ptr ident)
{
  if (ident->empty())
  {
    return NULL;
  }

  long hash = FnvHash::hashCode64(ident);
  return findSelectItem(hash);
}

SQLSelectItem_ptr SQLSelectQueryBlock::findSelectItem(long identHash)
{
  for (SQLSelectItem_ptr item : *this->selectList)
  {
    if (item->match(identHash))
    {
      return item;
    }
  }

  if (from == NULL)
  {
    return NULL;
  }

  if (selectList->size() == 1)
  {
    std::list<SQLSelectItem_ptr>::iterator it = selectList->begin();
    std::advance(it, 0);
    if (instanceof <SQLExpr, SQLAllColumnExpr>((*it)->getExpr()))
    {
      SQLTableSource_ptr matchedTableSource = from->findTableSourceWithColumn(identHash);
      if (matchedTableSource != NULL)
      {
        return (*it);
      }
    }
  }

  SQLSelectItem_ptr ownerAllItem = NULL;
  for (SQLSelectItem_ptr item : *this->selectList)
  {
    SQLExpr_ptr itemExpr = item->getExpr();
    //            if (itemExpr instanceof SQLAllColumnExpr && !(from instanceof SQLJoinTableSource)) {
    //                if (ownerAllItem != NULL) {
    //                    return NULL; // dup *
    //                }
    //                ownerAllItem = item;
    //                continue;
    //            }

    if (instanceof <SQLExpr, SQLPropertyExpr>(itemExpr) && (*((std::dynamic_pointer_cast<SQLPropertyExpr>(itemExpr))->getName()) == "*"))
    {
      if (ownerAllItem != NULL)
      {
        return NULL; // dup *
      }
      ownerAllItem = item;
    }
  }

  if (ownerAllItem != NULL)
  {
    return ownerAllItem;
  }

  return NULL;
}

BOOL_ptr SQLSelectQueryBlock::selectItemHasAllColumn()
{
  return selectItemHasAllColumn(BOOL::TRUE);
}

BOOL_ptr SQLSelectQueryBlock::selectItemHasAllColumn(BOOL_ptr recursive)
{
  for (SQLSelectItem_ptr item : *this->selectList)
  {
    SQLExpr_ptr expr = item->getExpr();

    bool allColumn = instanceof <SQLExpr, SQLAllColumnExpr>(expr) || (instanceof <SQLExpr, SQLPropertyExpr>(expr) && (*((std::dynamic_pointer_cast<SQLPropertyExpr>(expr))->getName()) == "*"));

    if (allColumn)
    {
      if (recursive && instanceof <SQLTableSource, SQLSubqueryTableSource>(from))
      {
        SQLSelect_ptr subSelect = (std::dynamic_pointer_cast<SQLSubqueryTableSource>(from))->select;
        // SQLSelectQueryBlock* queryBlock = subSelect->getQueryBlock();
        if (instanceof <SQLSelectQuery, SQLSelectQueryBlock>(subSelect->getQuery()))
        {
          SQLSelectQueryBlock_ptr queryBlock = std::dynamic_pointer_cast<SQLSelectQueryBlock>(subSelect->getQuery());
          if (queryBlock != NULL)
          {
            return queryBlock->selectItemHasAllColumn();
          }
        }
      }
      return BOOL::TRUE;
    }
  }

  return BOOL::FALSE;
}

SQLSelectItem_ptr SQLSelectQueryBlock::findAllColumnSelectItem()
{
  SQLSelectItem_ptr allColumnItem = NULL;
  for (SQLSelectItem_ptr item : *this->selectList)
  {
    SQLExpr_ptr expr = item->getExpr();

    bool allColumn = instanceof <SQLExpr, SQLAllColumnExpr>(expr) || (instanceof <SQLExpr, SQLPropertyExpr>(expr) && *((std::dynamic_pointer_cast<SQLPropertyExpr>(expr))->getName()) == "*");

    if (allColumnItem != NULL)
    {
      return NULL; // duplicateAllColumn
    }
    allColumnItem = item;
  }

  return allColumnItem;
}

// SQLColumnDefinition *SQLSelectQueryBlock::findColumn(string_ptr  columnName)
// {
//   if (from == NULL)
//   {
//     return NULL;
//   }

//   long hash = FnvHash::hashCode64(columnName);
//   return from->findColumn(hash);
// }

// SQLColumnDefinition *SQLSelectQueryBlock::findColumn(long columnNameHash)
// {
//   SQLObject* object = resolveColum(columnNameHash);
//   if (instanceof<SQLObject, SQLColumnDefinition>(object))
//   {
//     return dynamic_cast<SQLColumnDefinition *>(object);
//   }
//   else if (instanceof<SQLObject, SQLSelectItem>(object))
//   {
//     SQLExpr_ptr expr = (dynamic_cast<SQLSelectItem_ptr>(object))->getExpr();
//     if (instanceof<SQLExpr, SQLName>(expr))
//     {
//       return dynamic_cast<SQLColumnDefinition *>((dynamic_cast<SQLName_ptr >(expr))->getResolvedColumn());
//     }
//   }
//   return NULL;
// }

SQLObject_ptr SQLSelectQueryBlock::resolveColum(long columnNameHash)
{
  SQLSelectItem_ptr selectItem = findSelectItem(columnNameHash);
  if (selectItem != NULL)
  {
    SQLExpr_ptr selectItemExpr = selectItem->getExpr();
    if (instanceof <SQLExpr, SQLAllColumnExpr>(selectItemExpr))
    {
      SQLObject_ptr resolveColumn = from->resolveColum(columnNameHash);
      if (resolveColumn != NULL)
      {
        return resolveColumn;
      }
    }
    else if (instanceof <SQLExpr, SQLPropertyExpr>(selectItemExpr) && 
    *((std::dynamic_pointer_cast<SQLPropertyExpr>(selectItemExpr))->getName()) == "*")
    {
      SQLTableSource_ptr resolvedTableSource = (std::dynamic_pointer_cast<SQLPropertyExpr>(selectItemExpr))->getResolvedTableSource();
      if (instanceof <SQLTableSource, SQLSubqueryTableSource>(resolvedTableSource))
      {
        BOOL_ptr isParentTableSource = BOOL::FALSE;
        for (SQLObject_ptr parent = this->getParent();
             parent != NULL;
             parent = parent->getParent())
        {
          if (parent == resolvedTableSource)
          {
            isParentTableSource = BOOL::TRUE;
            break;
          }
        }

        if (isParentTableSource)
        {
          return NULL;
        }

        SQLObject_ptr resolveColumn = resolvedTableSource->resolveColum(columnNameHash);
        if (resolveColumn != NULL)
        {
          return resolveColumn;
        }
      }
    }

    return selectItem;
  }

  if (from != NULL)
  {
    return from->resolveColum(columnNameHash);
  }
  else
  {
    return NULL;
  }
}

void SQLSelectQueryBlock::addCondition(string_ptr conditionSql)
{
  if (conditionSql->empty() || conditionSql->length() == 0)
  {
    return;
  }

  SQLExpr_ptr condition = SQLUtils::toSQLExpr(conditionSql, dbType);
  addCondition(condition);
}

void SQLSelectQueryBlock::addCondition(SQLExpr_ptr expr)
{
  if (expr == NULL)
  {
    return;
  }

  this->setWhere(SQLBinaryOpExpr::and_(where, expr));
}

BOOL_ptr SQLSelectQueryBlock::removeCondition(string_ptr conditionSql)
{
  if (conditionSql->empty() || conditionSql->length() == 0)
  {
    return BOOL::FALSE;
  }

  SQLExpr_ptr condition = SQLUtils::toSQLExpr(conditionSql, dbType);

  return removeCondition(condition);
}

BOOL_ptr SQLSelectQueryBlock::removeCondition(SQLExpr_ptr condition)
{
  if (condition == NULL)
  {
    return BOOL::FALSE;
  }

  if (instanceof <SQLExpr, SQLBinaryOpExprGroup>(where))
  {
    SQLBinaryOpExprGroup_ptr group = std::dynamic_pointer_cast<SQLBinaryOpExprGroup>(where);

    int removedCount = 0;
    SQLExpr_list_ptr items = group->getItems();
    std::list<SQLExpr_ptr>::iterator it = items->begin();
    for (int i = items->size() - 1; i >= 0; i--)
    {
      std::advance(it, i);
      SQLExpr_ptr item = (*it);
      if (item == condition)
      {
        items->erase(it);
        removedCount++;
      }
    }
    if (items->empty())
    {
      where = NULL;
    }

    return (removedCount > 0)?BOOL::TRUE:BOOL::FALSE;
  }

  if (instanceof <SQLExpr, SQLBinaryOpExpr>(where))
  {
    SQLBinaryOpExpr_ptr binaryOpWhere = std::dynamic_pointer_cast<SQLBinaryOpExpr>(where);
    SQLBinaryOperator_ptr xoperator = binaryOpWhere->getOperator();
    if (xoperator->name->c_str() == SQLBinaryOperator::BooleanAnd.name->c_str() ||
        xoperator->name->c_str() == SQLBinaryOperator::BooleanOr.name->c_str())
    {
      SQLExpr_list_ptr items = SQLBinaryOpExpr::split(binaryOpWhere);

      int removedCount = 0;
      std::list<SQLExpr_ptr>::iterator it = items->begin();
      for (int i = items->size() - 1; i >= 0; i--)
      {
        std::advance(it, i);
        SQLExpr_ptr item = (*it);
        if (item == condition)
        {
          if (SQLUtils::replaceInParent(item, NULL))
          {
            removedCount++;
          }
        }
      }

      return (removedCount > 0)?BOOL::TRUE:BOOL::FALSE;
    }
  }

  if (condition == where)
  {
    where = NULL;
    return BOOL::TRUE;
  }

  return BOOL::FALSE;
}

void SQLSelectQueryBlock::limit(int rowCount, int offset)
{
  SQLLimit_ptr limit_ = SQLLimit_ptr(new SQLLimit());
  limit_->setRowCount(SQLIntegerExpr_ptr(new SQLIntegerExpr(rowCount)));
  if (offset > 0)
  {
    // boost::rational<int> a(offset);
    limit_->setOffset(SQLIntegerExpr_ptr(new SQLIntegerExpr(offset)));
  }

  setLimit(limit_);
}

string_ptr SQLSelectQueryBlock::getCachedSelectList()
{
  return cachedSelectList;
}

void SQLSelectQueryBlock::setCachedSelectList(string_ptr cachedSelectList, long cachedSelectListHash)
{
  this->cachedSelectList = cachedSelectList;
  this->cachedSelectListHash = cachedSelectListHash;
}

long SQLSelectQueryBlock::getCachedSelectListHash()
{
  return cachedSelectListHash;
}

DbType_ptr SQLSelectQueryBlock::getDbType()
{
  return dbType;
}

void SQLSelectQueryBlock::setDbType(DbType_ptr dbType)
{
  this->dbType = dbType;
}

SQLCommentHint_list_ptr SQLSelectQueryBlock::getHintsDirect()
{
  return hints;
}

SQLCommentHint_list_ptr SQLSelectQueryBlock::getHints()
{
  // if (hints == NULL)
  // {
  //   hints = new ArrayList<SQLCommentHint *>(2);
  // }
  return hints;
}

void SQLSelectQueryBlock::setHints(SQLCommentHint_list_ptr hints)
{
  this->hints = hints;
}

int SQLSelectQueryBlock::getHintsSize()
{
  if (hints->empty())
  {
    return 0;
  }

  return hints->size();
}

BOOL_ptr SQLSelectQueryBlock::replaceInParent(SQLSelectQuery *x)
{
  // if (parent instanceof SQLSelect) {
  //     ((SQLSelect) parent)->setQuery(x);
  //     return BOOL::TRUE;
  // }

  // if (parent instanceof SQLUnionQuery) {
  //     SQLUnionQuery union = (SQLUnionQuery) parent;
  //     return union->replace(this, x);
  // }

  return BOOL::FALSE;
}

SQLSelectOrderByItem_list_ptr SQLSelectQueryBlock::getClusterBy()
{
  // if (clusterBy == NULL)
  // {
  //   clusterBy = new ArrayList<SQLSelectOrderByItem_ptr >();
  // }

  return clusterBy;
}

SQLSelectOrderByItem_list_ptr SQLSelectQueryBlock::getClusterByDirect()
{
  return clusterBy;
}

void SQLSelectQueryBlock::addClusterBy(SQLSelectOrderByItem_ptr item)
{
  // if (clusterBy == NULL)
  // {
  //   clusterBy = new ArrayList<SQLSelectOrderByItem_ptr >();
  // }
  if (item != NULL)
  {
    item->setParent(SharedObject(SQLSelectQueryBlock));
  }
  this->clusterBy->push_back(item);
}

string_list_ptr SQLSelectQueryBlock::computeSelecteListAlias()
{
  string_list_ptr aliasList = std::make_shared<std::list<string_ptr>>();

  for (SQLSelectItem_ptr item : *this->selectList)
  {
    if (instanceof <SQLSelectItem, OdpsUDTFSQLSelectItem>(item))
    {
      // aliasList->addAll((dynamic_cast<OdpsUDTFSQLSelectItem *>(item))->getAliasList());
      for (string_ptr tmp : *(std::dynamic_pointer_cast<OdpsUDTFSQLSelectItem>(item))->getAliasList())
      {
        aliasList->push_back(tmp);
      }
    }
    else
    {
      SQLExpr_ptr expr = item->getExpr();
      if (instanceof <SQLExpr, SQLAllColumnExpr>(expr))
      {
        // TODO
      }
      else if (instanceof <SQLExpr, SQLPropertyExpr>(expr) && (*((std::dynamic_pointer_cast<SQLPropertyExpr>(expr))->getName()) == "*"))
      {
        // TODO
      }
      else
      {
        aliasList->push_back((item->computeAlias()));
      }
    }
  }

  return aliasList;
}

SQLTableSource_list_ptr  SQLSelectQueryBlock::getMappJoinTableSources()
{
  if (hints->empty())
  {
    SQLTableSource_list_ptr  tmp = std::make_shared<std::list<SQLTableSource_ptr>>();
    return tmp;
  }

  SQLTableSource_list_ptr  tableSources = std::make_shared<std::list<SQLTableSource_ptr>>();
  for (SQLCommentHint_ptr hint : *hints)
  {
    string_ptr text = hint->getText();
    if (text->at(0) == '+')
    {
      SQLExpr_ptr hintExpr = SQLUtils::toSQLExpr(make_string_ptr(text->substr(1)), dbType);
      if (instanceof <SQLExpr, SQLMethodInvokeExpr>(hintExpr))
      {
        SQLMethodInvokeExpr_ptr func = std::dynamic_pointer_cast<SQLMethodInvokeExpr>(hintExpr);
        if (func->methodNameHashCode64() == FnvHash::Constants::MAPJOIN)
        {
          for (SQLExpr_ptr arg : *func->getArguments())
          {
            SQLIdentifierExpr_ptr tablename = std::dynamic_pointer_cast<SQLIdentifierExpr>(arg);
            SQLTableSource_ptr tableSource = findTableSource(tablename->getName());
            // if (tableSources == NULL)
            // {
            //   tableSources = new ArrayList<SQLTableSource_ptr  >(2);
            // }
            tableSources->push_back(tableSource);
          }
        }
      }
    }
  }

  if (tableSources->empty())
  {
    SQLTableSource_list_ptr  tmp = std::make_shared<std::list<SQLTableSource_ptr>>();
    return tmp;
  }

  return tableSources;
}

BOOL_ptr SQLSelectQueryBlock::clearMapJoinHint()
{
  if (hints->empty())
  {
    return BOOL::FALSE;
  }

  int removeCount = 0;
  for (int i = hints->size() - 1; i >= 0; i--)
  {
    std::list<SQLCommentHint_ptr>::iterator it = hints->begin();
    std::advance(it, i);
    if (it != hints->end())
    {
      SQLCommentHint_ptr hint = (*it);
      string_ptr text = hint->getText();
      if (text->at(0) == '+')
      {
        SQLExpr_ptr hintExpr = SQLUtils::toSQLExpr(make_string_ptr(text->substr(1)), dbType);
        if (instanceof <SQLExpr, SQLMethodInvokeExpr>(hintExpr))
        {
          SQLMethodInvokeExpr_ptr func = std::dynamic_pointer_cast<SQLMethodInvokeExpr>(hintExpr);
          if (func->methodNameHashCode64() == FnvHash::Constants::MAPJOIN)
          {
            hints->erase(it); // 删除第i个元素
            removeCount++;
          }
        }
      }
    }
  }

  return (removeCount > 0)?BOOL::TRUE:BOOL::FALSE;
}
